﻿using System;
using System.Collections.Generic;

namespace PstBakup2013Server
{
    internal class SqlUploader
    {
        private SqlHelper _sqlHelper = SqlHelper.GetInstance();
        private System.Timers.Timer _timer = new System.Timers.Timer(10000);
        private Logger _logger = new Logger(@"C:\Windows\Temp\", "PstBackup2013SqlUploader.log");

        internal SqlUploader(string serverName, string databaseName, string username, string password)
        {
            this._sqlHelper.ServerName = serverName;
            this._sqlHelper.DataBaseName = databaseName;
            this._sqlHelper.Login = username;
            this._sqlHelper.Password = password;
            this.ShutingDown = false;
        }

        /// <summary>
        /// If set to true, this thread is going to shutdown.
        /// </summary>
        private bool ShutingDown { get; set; }

        /// <summary>
        /// Start to process awaiting messages.
        /// </summary>
        internal void Start()
        {
            this._timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
            this._timer.Enabled = true;
            this._timer.Start();
        }

        /// <summary>
        /// Stop to process messages
        /// </summary>
        internal void Stop()
        {
            this._timer.Stop();
            this.ShutingDown = true;
        }

        /// <summary>
        /// Get a CSV list of all registered clients.
        /// </summary>
        /// <returns>A CSV formatted list of all clients. Format : [ClientID;ComputerName;UserName;LastContactDate;ClientVersion]</returns>
        internal string GetAllClientsList()
        {
            string result = String.Empty;

            try
            {
                lock (Server.clientMessages)
                {
                    result = this._sqlHelper.GetAllClientsList();
                }
            }
            catch (Exception) { }

            return result;
        }

        /// <summary>
        /// Get a CSV list of all registered clients with a specific version.
        /// </summary>
        /// <param name="version">Version for which clients to search for.</param>
        /// <returns>A CSV formatted list of all clients with this version. Format : [ClientID;ComputerName;UserName;LastContactDate;ClientVersion]</returns>
        internal string GetAllClientsForVersion(string version)
        {
            string result = String.Empty;

            try
            {
                lock (Server.clientMessages)
                {
                    result = this._sqlHelper.GetAllClientsForVersion(version);
                }
            }
            catch (Exception) { }

            return result;
        }

        /// <summary>
        /// Get a CSV formatted list of all clients with a specific destination
        /// </summary>
        /// <param name="destination">Destination set into clients</param>
        /// <returns>A CSV formatted list of clients</returns>
        internal string GetAllClientsForDestination(string destination)
        {
            string result = String.Empty;

            try
            {
                lock (Server.clientMessages)
                {
                    result = this._sqlHelper.GetAllClientsForDestination(destination);
                }
            }
            catch (Exception) { }

            return result;
        }

        /// <summary>
        /// Get the list of all Pst File for the client.
        /// </summary>
        /// <param name="clientID">Guid of the client.</param>
        /// <returns>A list of <see cref="PstFile"/></returns>
        internal List<PstFile> GetAllPstFilesForClient(string clientID)
        {
            List<PstFile> result = new List<PstFile>();

            try
            {
                lock (Server.clientMessages)
                {
                    result = this._sqlHelper.GetAllPstFilesForClient(clientID);
                }
            }
            catch (Exception) { }

            return result;
        }

        /// <summary>
        /// Query the database for all unique destinations.
        /// </summary>
        /// <returns>A List of unique destinations.</returns>
        internal List<String> GetAllDestinations()
        {
            List<String> result = new List<String>();

            try
            {
                lock (Server.clientMessages)
                {
                    result = this._sqlHelper.GetAllDestinations();
                }
            }
            catch (Exception) { }

            return result;
        }

        /// <summary>
        /// Query the database for all unique Versions.
        /// </summary>
        /// <returns>A List of unique Versions.</returns>
        internal List<String> GetAllVersions()
        {
            List<String> result = new List<String>();

            try
            {
                lock (Server.clientMessages)
                {
                    result = this._sqlHelper.GetAllVersions();
                }
            }
            catch (Exception) { }

            return result;
        }

        /// <summary>
        /// Get a CSV formatted list of all ResultID with their meaning
        /// </summary>
        /// <returns>A CSV formatted list of ResultID with their meaning</returns>
        internal String GetResultIDs()
        {
            string result = String.Empty;

            try
            {
                lock (Server.clientMessages)
                {
                    result = this._sqlHelper.GetResultIDs();
                }
            }
            catch (Exception) { }

            return result;
        }

        private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            this._timer.Enabled = false;

            if (!this.ShutingDown)
            {
                lock (Server.clientMessages)
                {
                    if (Server.clientMessages.Count != 0)
                    {
                        _logger.WriteLog(Server.clientMessages.Count + " message(s) are queued.");
                        this.SendMessagesToSql();
                    }
                }
            }

            this._timer.Enabled = true;
        }

        private void SendMessagesToSql()
        {
            lock (Server.clientMessages)
            {
                while (Server.clientMessages.Count != 0)
                {
                    try
                    {
                        if (!this.ShutingDown)
                        {
                            ClientMessage clientMessage = new ClientMessage(Server.clientMessages[0]);
                            _logger.WriteLog(clientMessage.ComputerName + " have send " + clientMessage.PstFiles.Count + " Pst Files.");

                            string computerName = clientMessage.ComputerName;
                            string username = clientMessage.UserName;
                            string clientID = clientMessage.ClientID;
                            Version clientVersion = clientMessage.ClientVersion;
                            DateTime sentDate = clientMessage.SentDate;

                            bool clientRegistered = true;

                            if (!this._sqlHelper.ClientExists(clientID)) // new client, register it
                            {
                                _logger.WriteLog(clientMessage.ComputerName + " is a new client.");
                                clientRegistered = this._sqlHelper.RegisterNewClient(clientID, computerName, username, sentDate, clientVersion);
                            }

                            if (clientRegistered)
                                foreach (PstFile pstFile in clientMessage.PstFiles)
                                {
                                    if (!this._sqlHelper.PstFileExists(clientID, pstFile.LocalPath)) // new PST file, register it
                                    {
                                        _logger.WriteLog(pstFile.LocalPath + " is a new PST File.");
                                        this._sqlHelper.RegisterNewPstFile(clientID, pstFile);
                                    }
                                    else
                                    {
                                        DateTime lastDateSaved = this._sqlHelper.GetLastDateSaved(clientID, pstFile.LocalPath);
                                        if (pstFile.ResultID == 0)  // successfull backup
                                        {
                                            if (DateTime.Compare(pstFile.EndTime, lastDateSaved) == 1)   // This message show that this backup overwrite a previous successfull backup. Update database record
                                                this._sqlHelper.UpdatePstFileRecord(clientID, pstFile, pstFile.EndTime);    // Update the LastDateSaved in the database record.
                                        }
                                        else    // Error while backup
                                        {
                                            if (DateTime.Compare(pstFile.EndTime, lastDateSaved) == 1)  // this message show that an error occurred after a successfull backup. Update database record
                                                this._sqlHelper.UpdatePstFileRecord(clientID, pstFile, lastDateSaved);  // Do not change LastDateSaved in the database record
                                        }
                                    }
                                }
                        }
                    }
                    catch (Exception ex) { _logger.WriteLog("An error occurs while sending message to SQL : " + ex.Message); }

                    Server.clientMessages.RemoveAt(0);
                }
            }
        }
    }
}
